var BOARD_HEIGHT=10, BOARD_WIDTH=10, TILE_SIZE='40';

var TILE_STATE = {
			COVERED : {representation : 'COVERED', class : 'covered'},
                        EMPTY   : {representation : 'CLEARED', class : 'empty'},
			MINE    : {representation : 'MINE', class : 'mine'}
                  };

$(document).ready(function() {
	startGame();
});

function startGame(){
	var game = createGame(BOARD_WIDTH, BOARD_HEIGHT); 
        var board = generateBoard(game);
        board.display();
        game.on('update', function(boardState){
                board.updateState(boardState);  
        });
        game.on('lose', function(){
                $('.tile').unbind('mouseup');
        });
        game.on('win', function(message) {
                window.alert('you have won. hurrah. Time taken:' + message.duration );
                $('.tile').unbind('mouseup');
        });
        game.on('error', function(message) {
                window.alert(message);
        });
}


function generateBoard(game) {
	var generateId = idGenerator();
	return {
		grid : utils.fillArray(BOARD_HEIGHT, function() {return utils.fillArray(BOARD_WIDTH,createTile(generateId));}),
		coordsById : function(id) {
			var y = Math.floor(id / BOARD_WIDTH);
			var x = id - (BOARD_WIDTH * y);
			return {x : x, y : y};
		},
		html : function () {
			var html = "";
			for (var y=0; y<this.grid.length;y++){
				for (var x=0; x<this.grid[y].length; x++){
					html+=this.grid[y][x].html();
				}
			}
			return html;
		},
		touch : function(id) {
			var coords = this.coordsById(id);
			if (!this.grid[coords.y][coords.x].isFlagged()){
				game.touch(coords);
			}
		},
		slam : function(id) {
			game.slam(this.coordsById(id)); 
		},
		flag : function(id) {
			var coords = this.coordsById(id);
			if (this.grid[coords.y][coords.x].state === TILE_STATE.COVERED) {
				this.grid[coords.y][coords.x].toggleFlag();
				game.flag(coords);
				this.display();
			}
		},
		display : function () {
			var board = this;
			$('#board').html(this.html());
		        $('#board').css({'width': ((BOARD_WIDTH + 1) * TILE_SIZE) -1 + 'px'});
		        $('.tile').css({'width': TILE_SIZE + 'px', 'height': TILE_SIZE + 'px'});
			$('.tile').bind('contextmenu', function () {return false;});
			var leftBeingClicked,rightBeingClicked;
			$('.tile').mousedown(function (event) {
				switch (event.which) {
					case 1:
						leftBeingClicked = true;
						break;
					case 3:
						rightBeingClicked = true;
						break;
				}	
			});
			$('.tile').mouseup(function(event) {
			      	var id = $(this).attr('id');

				if (leftBeingClicked && rightBeingClicked) {
					board.slam(id);
					return;
				}

				switch (event.which) {
     				   case 1:
                                 	board.touch(id);
					leftBeingClicked = false;
					break;
        			   case 3:
					board.flag(id);
					rightBeingClicked = false;
					break;
   				 }
         		});
		},
		updateState : function(json) {
			_(json.grid).chain().zip(this.grid).map(function (row) {
				_(row[0]).chain().zip(row[1]).map(function(tilePair){
					var tile = tilePair[1];
					var state = tilePair[0];
					tile.state = stateByServerRepresentation(state.state);
					if (state.numberOfAdjacentMines !== '?' && state.numberOfAdjacentMines !== 0) {
						tile.text = state.numberOfAdjacentMines;
					}
				});
			});
			this.display();
		}
	}
}

function idGenerator() {
	var id = 0;
	return function(){
		return id++;
	};
}

function createTile(generateId) {
	return function() {
		return {
			id : generateId(),
			text : '',
			state : TILE_STATE.COVERED,
			flagged : false,
			toggleFlag : function () {
				this.flagged = !this.flagged;
			},	
			isFlagged : function () {
				return this.flagged;
			},
			flagClass : function () {
				return this.flagged && this.state === TILE_STATE.COVERED ? 'flagged' : '';
			},
			html : function(){
				return "<button class='tile " + this.state.class + " " + this.flagClass() + "' id='" + this.id + "'>"+ this.text +" </button>";
			}
		}
	};
};
		
	
function stateByServerRepresentation(serverRepresentation){
	for (var state in TILE_STATE) {
		if (TILE_STATE[state].representation === serverRepresentation) {
			return TILE_STATE[state];
		}
	}
	throw 'No TILE_STATE found for ' + representation;
}
